package cn.edu.qfnu.common.dao;

import cn.edu.qfnu.common.paginate.Pagination;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public abstract class BaseDaoHib<T, ID extends Serializable> implements BaseDao<T, ID> {

    // 当检索所有列表时返回的记录最大值，避免内存溢出的情况
	private static final int MAX_NUM_OF_RESULTS = 200;
	
	private Class<T> clazz;

	@Autowired
	private SessionFactory sessionFactory;


    @SuppressWarnings("unchecked")
	public BaseDaoHib() {
        Type t = this.getClass().getGenericSuperclass();
        if (t instanceof ParameterizedType) {
            Type[] p = ((ParameterizedType) t).getActualTypeArguments();
            this.clazz = (Class<T>) p[0];
        }
	}
	
	protected Session currentSession(){
		return sessionFactory.getCurrentSession();
	}
	
	@Override
	public void save(T entity) {
		currentSession().save(entity);
	}

	@Override
	public void removeById(ID id) {
		T entity = load(id);
		currentSession().delete(entity);
	}

	@Override
	public void remove(T entity){
	    currentSession().delete(entity);
	}
	
	@Override
	public void saveOrUpdate(T entity) {
	    currentSession().clear();
		currentSession().saveOrUpdate(entity);
	}

	@Override
	@SuppressWarnings("unchecked")
	public T get(ID id){
        return currentSession().get(clazz, id);
	}
	
	@Override
	@SuppressWarnings("unchecked")
	public T load(ID id) {
		return currentSession().load(clazz, id);
	}

    @Override
    public void merge(T entity) {
	    currentSession().merge(entity);
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> query() {

	    DetachedCriteria detachedCriteria = DetachedCriteria.forClass(clazz);

	    Criteria criteria = detachedCriteria.getExecutableCriteria(currentSession());
        criteria.setMaxResults(MAX_NUM_OF_RESULTS);

        return (List<T>)criteria.list();
    }


    @Override
    @SuppressWarnings("unchecked")
    public List<T> queryPagedListByDetachedCriteria(DetachedCriteria detachedCriteria,
                                                    Pagination pagination) {
        Criteria criteria = detachedCriteria.
                getExecutableCriteria(currentSession());

        if (pagination.getTotal() == 0) {
            criteria.setProjection(Projections.projectionList()
                    .add(Projections.rowCount()));
            pagination.setTotal((Long)criteria.uniqueResult());

        }

        criteria.setProjection(null);

        criteria.setFirstResult(pagination.getFirst());
        criteria.setMaxResults(pagination.getPageSize());

        return criteria.list();
    }

    @Override
    @SuppressWarnings("unchecked")
    public List<T> queryByDetachedCriteria(DetachedCriteria detachedCriteria) {
        return detachedCriteria
                .getExecutableCriteria(currentSession())
                .setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)  //对查询的结果去重
                .list();
    }
	
}
